/**
在TypeScript中，泛型参数使用约束是一种机制，允许开发者对泛型类型参数的类型范围进行限制，从而确保类型安全性。这种约束可以帮助开发者在使用泛型时，确保传入的类型符合某些条件。
  1. 基本概念
  - 泛型参数约束允许开发者指定一个基类或接口，确保传入的类型必须符合该基类或接口的结构。

  2. 使用接口进行约束
  - 可以使用接口来约束泛型参数，确保传入的类型实现了特定的属性或方法。

    例如：
  interface Lengthwise {
      length: number; // 定义一个包含length属性的接口
  }

  function logLength<T extends Lengthwise>(arg: T): void {
      console.log(arg.length); // 只有具有length属性的类型才能传入
  }

  logLength("Hello"); // 合法，字符串有length属性
  logLength([1, 2, 3]); // 合法，数组有length属性
  // logLength(123); // 错误：number类型没有length属性
  3. 使用类进行约束
  - 也可以使用类作为约束，确保泛型参数是该类或其子类的实例。

    例如：
  class Animal {
      name: string;

      constructor(name: string) {
          this.name = name;
      }
  }

  class Dog extends Animal {
      bark() {
          console.log("Woof!");
      }
  }

  function createInstance<T extends Animal>(c: new () => T): T {
      return new c(); // 只允许Animal及其子类的构造函数
  }

  const dog = createInstance(Dog); // 合法
  // const instance = createInstance(Date); // 错误：Date不是Animal的子类
  4. 多重约束
  - 可以对一个泛型参数设置多个约束，但需要使用交叉类型（ `&` ）来实现。

    例如：
  interface Nameable {
      name: string;
  }

  interface Ageable {
      age: number;
  }

  function printInfo<T extends Nameable & Ageable>(obj: T): void {
      console.log(`Name: ${obj.name}, Age: ${obj.age}`);
  }

  const person = { name: "Alice", age: 30 };
  printInfo(person); // 合法
  // printInfo({ name: "Bob" }); // 错误：缺少age属性
  5. 总结
  泛型参数使用约束是TypeScript中一个重要的特性，它通过限制泛型参数的类型范围，确保了类型的安全性和一致性。通过使用接口、类和交叉类型进行约束，开发者可以创建更加灵活和可靠的函数和类，提高代码的可维护性和可读性。约束泛型参数在处理复杂数据结构和实现通用算法时尤为重要。
 */

interface IPerson {
  name: string;
  age: number;
}

type IPersonKeys = keyof IPerson; // 'age' | 'name'

function getObjectProperty<O, K extends keyof O>(obj: O, key: K) {
  return obj[key];
}

const info = {
  name: "person-name",
  age: 18,
  height: 1.88,
}

const name = getObjectProperty(info, "name"); // string

export {}
